// server_main.cpp
#include "server_core.h"
#include "user_manager.h"
#include "room_manager.h"
#include "utils.h"

#include <iostream>
#include <vector>
#include <csignal>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <fstream>

using namespace std;

vector<int> client_fds;
RoomManager room_manager;
bool server_running = true;
int global_server_fd = -1;

void handle_sigint() {
    cout << "\nServer shutting down..." << endl;
    if (global_server_fd != -1) close(global_server_fd);
    log_to_file("Server shutdown by SIGINT.\n");
    cout << "\033[0m" << flush;
    exit(0);
}

void run_server(int port) {
    ofstream clear("chat_log.txt", ios::out); 
    clear.close();

    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) { perror("socket failed"); exit(1); }

    signal(SIGINT, handle_sigint);
    global_server_fd = server_fd;

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_fd, (const sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind failed"); exit(1); }
    if (listen(server_fd, 10) < 0) { perror("listen"); exit(1); }

    fd_set all_set, read_set;
    FD_ZERO(&all_set);
    FD_SET(server_fd, &all_set);
    int max_fd = server_fd;

    cout << "Server listening on port " << port << "..." << endl;

    while (server_running) {
        read_set = all_set;
        if (select(max_fd + 1, &read_set, nullptr, nullptr, nullptr) < 0) break;

        // 新连接
        if (FD_ISSET(server_fd, &read_set)) {
            sockaddr_in cli_addr{};
            socklen_t len = sizeof(cli_addr);
            int client_fd = accept(server_fd, (sockaddr*)&cli_addr, &len);
            if (client_fd < 0) continue;

            struct timeval timeout {10, 0};
            setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

            char name_buf[32];
            int n = recv(client_fd, name_buf, sizeof(name_buf) - 1, 0);
            if (n <= 0) {
                string tip = color_wrap("[Server] No nickname received. Connection closed.\n", Color::RED);
                send(client_fd, tip.c_str(), tip.size(), 0);
                close(client_fd);
                continue;
            }

            name_buf[n] = '\0';
            string nickname = name_buf;

            if (is_nickname_taken(nickname)) {
                string msg = color_wrap("[Server] Nickname already in use.\n", Color::RED);
                send(client_fd, msg.c_str(), msg.size(), 0);
                close(client_fd);
                continue;
            }

            add_user(client_fd, nickname);
            client_fds.push_back(client_fd);
            FD_SET(client_fd, &all_set);
            max_fd = max(max_fd, client_fd);

            string err;
            room_manager.join(client_fd, "lobby", "", err);

            string msg = color_wrap(get_current_time() + " [Server] " + nickname + " joined.\n", Color::GREEN);
            broadcast(client_fd, msg);
            send(client_fd, msg.c_str(), msg.size(), 0);
            cout << msg;
            log_to_file(msg);
        }

        // 客户端消息
        for (size_t i = 0; i < client_fds.size(); ++i) {
            int fd = client_fds[i];
            if (!FD_ISSET(fd, &read_set)) continue;

            char buf[1024];
            int n = recv(fd, buf, sizeof(buf) - 1, 0);
            if (n <= 0) {
                string left = color_wrap(get_current_time() + " [Server] " + get_nickname(fd) + " left.\n", Color::YELLOW);
                broadcast(fd, left);
                cout << left;
                log_to_file(left);
                FD_CLR(fd, &all_set);
                close(fd);
                remove_user(fd);
                room_manager.leave(fd);
                client_fds.erase(client_fds.begin() + i);
                --i;
                continue;
            }

            buf[n] = '\0';
            string msg(buf);
            handle_message(fd, msg, all_set, i);
        }
    }

    close(server_fd);
    cout << "\033[0m" << flush;
}

int main(int argc, char* argv[]) {
    int port = 8888;
    if (argc == 2) port = atoi(argv[1]);
    run_server(port);
    return 0;
}

